use std::{
    env,
    sync::{
        atomic::{AtomicBool, AtomicU32},
        Arc, Mutex,
    },
    time::Duration,
};

use realman::{
    traits::{ArmStateTrait, IOTrait, ModbusTrait},
    Realman,
};
use server::AppState;

mod api;
mod config;
mod error;
mod router;
mod server;
mod utils;

pub use error::Error;

type Result<T> = std::result::Result<T, error::Error>;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();

    // test
    // let (car_listen, _) = std::sync::mpsc::channel::<(f64, f64)>();

    // car
    let serial_port = env::var(config::SERIAL_PORT).unwrap_or("/dev/ttyUSB0".to_string());
    let car_listen = chongyoucar::connect(&serial_port)?;

    // arm
    let mut arm_listen = Realman::default().connect()?;
    arm_listen
        .set_tool_voltage(realman::VoltageType::Three)
        .ok();
    // 配置末端ModbusRTU模式
    arm_listen
        .set_modbus_mode(
            realman::PortType::EndRS485RTUMain,
            realman::BaudrateType::Baud115200,
            1,
        )
        .ok();
    // 机械臂监听
    let arm_listen = Arc::new(Mutex::new(arm_listen));
    // 机械臂关节角度
    let arm_joint = Arc::new(Mutex::new(vec![0; 7]));
    // 线程clone
    // let arc_listen_clone = arm_listen.clone();
    // let arm_joint_clone = arm_joint.clone();
    // tokio::spawn(async move {
    //     loop {
    //         if let Ok(mut arm) = arc_listen_clone.lock() {
    //             if let Ok(data) = arm.get_joint_degree() {
    //                 if let Ok(mut joint) = arm_joint_clone.lock() {
    //                     // println!("{:?}", data.joint);
    //                     *joint = data.joint;
    //                 }
    //             }
    //         }
    //         std::thread::sleep(Duration::from_millis(500));
    //     }
    // });

    // web
    let port = env::var(config::PORT).map_or(config::DEFAULT_PORT, |v| {
        v.parse().unwrap_or(config::DEFAULT_PORT)
    });
    let tcp_listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", port)).await?;

    let app = router::router(AppState {
        car_listen,
        arm_listen,
        arm_joint,
        is_record: AtomicBool::new(true),
        speed: AtomicU32::new(100),
    });

    axum::serve(tcp_listener, app).await?;

    Ok(())
}
